﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using Bestcode.MathParser;
using Tubes4_Metnum.Machine;
using ExpressionPlotterControl;

namespace Tubes4_Metnum
{
    public partial class MainForm : Form
    {
        private ResultForm resultForm;

        private Trapesium trapesium;
        private TitikTengah titiktengah;
        private GaussLegendre gausslegendre;
        private Simpson1per3 simpson1per3;
        private Simpson3per8 simpson3per8;
        private Romberg romberg;

        private MetodeEnum metode;
        private SoalEnum soal;
        private String exp;
        private String exp2;
        private double hasil;
        private double hasil2;
        private String hasil1text;
        private String hasil2text;
        private String[] columnHeader;
        private String[] columnName;
        private double[][] dataIterasi;

        private double[] tempDataDebitSiang;
        private double[] tempDataDebitMalam;

        public ProgramUtil programUtil;

        public MainForm()
        {
            InitializeComponent();
            InitializeMetode();
            InitializeVariable();
            InitializeTab();

            //gausslegendre.Integral(2, "1/(1+x)", 0.0, 1.0);
            //Console.WriteLine("Test Gauss n-2: "+gausslegendre.result);
            //gausslegendre.Integral(3, "1/(1+x)", 0.0, 1.0);
            //Console.WriteLine("Test Gauss n-3: " + gausslegendre.result);
            //gausslegendre.Integral(4, "1/(1+x)", 0.0, 1.0);
            //Console.WriteLine("Test Gauss n-4: " + gausslegendre.result);
            //gausslegendre.Integral(5, "1/(1+x)", 0.0, 1.0);
            //Console.WriteLine("Test Gauss n-5: " + gausslegendre.result);
            //gausslegendre.Integral(6, "1/(1+x)", 0.0, 1.0);
            //Console.WriteLine("Test Gauss n-6: " + gausslegendre.result);
        }

        private void InitializeMetode()
        {
            trapesium = new Trapesium();
            titiktengah = new TitikTengah();
            gausslegendre = new GaussLegendre();
            simpson1per3 = new Simpson1per3();
            simpson3per8 = new Simpson3per8();
            romberg = new Romberg();
        }

        private void InitializeVariable()
        {
            metode = MetodeEnum.Trapesium;
            soal = SoalEnum.Matematika;
            exp = null;
            exp2 = null;
            hasil = 0.0f;
            hasil2 = 0.0f;
            hasil1text = null;
            hasil2text = null;
            columnHeader = new String[1];
            columnName = new String[1];
            dataIterasi = new double[1][];
            dataIterasi[0] = new double[] { 1 };
            tempDataDebitSiang = new double[] { 74, 85, 106, 115, 94, 88, 91, 110, 123, 142 };
            tempDataDebitMalam = new double[] { 153, 121, 80, 77, 54, 42, 38, 34, 45, 66 };
            programUtil = new ProgramUtil();
        }

        private void InitializeTab()
        {
            // Bidang Matematika
            metodeMatematika.Items.AddRange(new String[] { "Kaidah Trapesium", "Kaidah Titik-Tengah", "Kaidah Simpson 1/3",
                "Kaidah Simpson 3/8", "Metode Romberg", "Metode Gauss-Legrende orde .." });
            // Bidang Fisika 1
            metodeFisika1.Items.AddRange(new String[] { "Kaidah Trapesium", "Kaidah Simpson 3/8", "Metode Romberg", 
                "Metode Gauss-Legrende orde 4" });
            // Integral Ganda
            metodeIntegralGanda.Items.AddRange(new String[] { "Kaidah Trapesium", "Kaidah Simpson 1/3", 
                "Metode Gauss-Legrende orde 2" });
            // Bidang Kimia
            dataGridP_CKimia.ColumnCount = 2;
            dataGridP_CKimia.Columns[0].HeaderText = "P (atm)";
            dataGridP_CKimia.Columns[0].Name = "ColumnP";
            dataGridP_CKimia.Columns[1].HeaderText = "C";
            dataGridP_CKimia.Columns[1].Name = "ColumnC";
            double[] tempPKimia = programUtil.PKimiaArray;
            double[] tempCKimia = programUtil.CKimiaArray;
            for (int i = 0; i < tempPKimia.Length; i++) 
            {
                dataGridP_CKimia.Rows.Add(new String[] { tempPKimia[i].ToString(), tempCKimia[i].ToString() });
            }

            metodeKimia.Items.AddRange(new String[] { "Kaidah Trapesium", "Kaidah Simpson 1/3", "Metode Romberg",
                "Metode Gauss-Legrende orde .." });
            // Bidang Transportasi
            dataGridDebit_TTransportasi.ColumnCount = 2;
            dataGridDebit_TTransportasi.Columns[0].HeaderText = "Siang (6-16)";
            dataGridDebit_TTransportasi.Columns[0].Name = "ColumnSiang";
            dataGridDebit_TTransportasi.Columns[1].HeaderText = "Malam (18-4)";
            dataGridDebit_TTransportasi.Columns[1].Name = "ColumnMalam";
            for (int i = 0; i < tempDataDebitSiang.Length; i++)
            {
                dataGridDebit_TTransportasi.Rows.Add(tempDataDebitSiang[i].ToString(), tempDataDebitMalam[i].ToString());                
            }
            
            metodeTransportasi.Items.AddRange(new String[] { "Kaidah Trapesium", "Kaidah Simpson 1/3", "Kaidah Simpson 3/8" });
            // Bidang Fisika 2 (Tidak ada inisialisasi)
            // Bidang Kelistrikan
            metodeKelistrikan.Items.AddRange(new String[] { "Kaidah Trapesium", "Kaidah Simpson 1/3", "Metode Romberg", 
                "Metode Gauss-Legrende orde .." });
        }

        #region TabEnter
        private void tabBidangMatematika_Enter(object sender, EventArgs e)
        {
            metodeMatematika.SelectedIndex = 0;
            NMatematikaNumericUpDown.Value = 1;
        }

        private void tabBidangFisika1_Enter(object sender, EventArgs e)
        {
            metodeFisika1.SelectedIndex = 0;
            IntervalFisika1ComboBox.SelectedIndex = 0;
            TFisika1ComboBox.SelectedIndex = 0;
            NFisika1NumericUpDown.Value = 1;
        }

        private void tabIntegralGanda_Enter(object sender, EventArgs e)
        {
            metodeIntegralGanda.SelectedIndex = 0;
            NIntegralGandaNumericUpDown.Value = 1;
        }

        private void tabBidangKimia_Enter(object sender, EventArgs e)
        {
            metodeKimia.SelectedIndex = 0;
            NKimiaNumericUpDown.Value = 1;
        }

        private void tabBidangTransportasi_Enter(object sender, EventArgs e)
        {
            metodeTransportasi.SelectedIndex = 0;
        }

        private void tabBidangFisika2_Enter(object sender, EventArgs e)
        {
            // Do Nothing
        }

        private void tabBidangKelistrikan_Enter(object sender, EventArgs e)
        {
            metodeKelistrikan.SelectedIndex = 0;
            NKelistrikanNumericUpDown.Value = 1;
        }
        #endregion

        #region HitungButtonClick
        private void HitungMatematikaButton_Click(object sender, EventArgs e)
        {
            soal = SoalEnum.Matematika;
            exp = "exp(-1*x)/(1+sqrt(x)+x^2)";
            exp2 = null;
            int orde = (metode == MetodeEnum.GaussLegrende) ? (int)OrdeGaussMatematikaNumericUpDown.Value : 0;
            int n = (int)NMatematikaNumericUpDown.Value;
            // a = 0, b = 100, h = 0, n, orde
            HitungIntegral(0, 100, 0, n, orde);
        }

        private void HitungFisika1Button_Click(object sender, EventArgs e)
        {
            soal = SoalEnum.Fisika1;
            double a = 0.0001; // 1 x 10^-3
            double b = 10;
            int T = 10;
            int orde = (metode == MetodeEnum.GaussLegrende) ? 4 : 0;
            int n = (int)NFisika1NumericUpDown.Value;

            if (IntervalFisika1ComboBox.SelectedIndex == 1)
            {
                a = 100; b = 110;
            }
            else if (IntervalFisika1ComboBox.SelectedIndex == 2)
            {
                a = 1000; b = 1010;
            }
            else if (IntervalFisika1ComboBox.SelectedIndex == 3)
            {
                b = 100000; // inf = 100,000;
            }

            if (TFisika1ComboBox.SelectedIndex == 1)
            {
                T = 100;
            }
            else if (TFisika1ComboBox.SelectedIndex == 2)
            {
                T = 1000;
            }

            exp = programUtil.CreateFisika1Exp(a, b, T);
            exp2 = null;
            // a, b, h = 0, n, orde
            HitungIntegral(a, b, 0, n, orde);
        }

        private void HitungIntegralGandaButton_Click(object sender, EventArgs e)
        {
            soal = SoalEnum.IntegralGanda;
            exp = "(x^3)*y";
            exp2 = null;
            int orde = (metode == MetodeEnum.GaussLegrende) ? 2 : 0;
            int nx = (int)NIntegralGandaNumericUpDown.Value;
            int ny = (int)NIntegralGandaNumericUpDown.Value;
            // {ax = 0, ay = 0}, {bx = 1, by = 1}, h = 0, {nx,ny}, orde
            HitungIntegralGanda(new double[] { 0, 0 }, new double[] { 1, 1 }, 0, new int[] { nx, ny }, orde);
        }

        private void HitungKimiaButton_Click(object sender, EventArgs e)
        {
            soal = SoalEnum.Kimia;
            int orde = (metode == MetodeEnum.GaussLegrende) ? (int)OrdeGaussKimiaNumericUpDown.Value : 0;
            int n = (int) NKimiaNumericUpDown.Value;
            double P = Double.Parse(dataGridP_CKimia.SelectedCells[0].Value.ToString());
            exp = programUtil.CreateKimiaExp(9);
            exp2 = null;
            // a = 0.0001, b = P, h = 0, n, orde
            HitungIntegral(0.0001, P, 0, n, orde);
        }

        private void HitungTransportasiButton_Click(object sender, EventArgs e)
        {
            soal = SoalEnum.Transportasi;
            exp = null;
            exp2 = null;
            if (tempDataDebitSiang.Length > 1)
            {
                // a = 1, b = tempDataDebitSiang.Length / tempDataDebitMalam.Length, h = 0,
                // n = tempDataDebitSiang.Length - 1, orde = 0
                HitungIntegral(1, tempDataDebitSiang.Length, 0,
                    tempDataDebitSiang.Length - 1, 0);
            }
            else
            {
                // ERROR INFO
                MessageBox.Show("Jumlah Debit Kendaraan minimal 2");
            }
        }

        private void HitungFisika2Button_Click(object sender, EventArgs e)
        {
            soal = SoalEnum.Fisika2;
            exp = programUtil.CreateFisika2Exp();
            exp2 = null;
            double[] dataX, dataY;
            programUtil.CreateDataFisika2(out dataX, out dataY);
            // a = dataX[0], b = dataX[dataX.Length - 1], h = 0, n = dataX.Length - 1, orde = 0
            metode = programUtil.FindMetode(dataX.Length - 1);
            HitungIntegral(dataX[0], dataX[dataX.Length - 1], 0, dataX.Length - 1, 0);
        }

        private void HitungKelistrikanButton_Click(object sender, EventArgs e)
        {
            soal = SoalEnum.Kelistrikan;
            String[] exp_array = programUtil.CreateKelistrikanExp(1.00); // T = 1.00
            exp = exp_array[0];
            exp2 = exp_array[1];
            int orde = (metode == MetodeEnum.GaussLegrende) ? (int)OrdeGaussKelistrikanNumericUpDown.Value : 0;
            int n = (int)NKelistrikanNumericUpDown.Value;
            // a = 0, b = 1, h = 0, n, orde
            HitungIntegral(0, 1, 0, n, orde);
        }
        #endregion

        #region ComboBoxSelected
        private void metodeMatematika_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (metodeMatematika.SelectedIndex)
            {
                case 0:
                    {
                        metode = MetodeEnum.Trapesium;
                        break;
                    }
                case 1:
                    {
                        metode = MetodeEnum.TitikTengah;
                        break;
                    }
                case 2:
                    {
                        metode = MetodeEnum.Simpson1per3;
                        break;
                    }
                case 3:
                    {
                        metode = MetodeEnum.Simpson3per8;
                        break;
                    }
                case 4:
                    {
                        metode = MetodeEnum.Romberg;
                        break;
                    }
                case 5:
                    {
                        metode = MetodeEnum.GaussLegrende;
                        break;
                    }
            }

            if (metodeMatematika.SelectedIndex == 5) // Metode Gauss Legrende
            {
                OrdeGaussMatematikaLabel.Visible = true;
                OrdeGaussMatematikaNumericUpDown.Visible = true;
            }
            else
            {
                OrdeGaussMatematikaLabel.Visible = false;
                OrdeGaussMatematikaNumericUpDown.Visible = false;
                OrdeGaussMatematikaNumericUpDown.Value = 2;
            }
        }

        private void metodeFisika1_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (metodeFisika1.SelectedIndex)
            {
                case 0:
                    {
                        metode = MetodeEnum.Trapesium;
                        break;
                    }
                case 1:
                    {
                        metode = MetodeEnum.Simpson3per8;
                        break;
                    }
                case 2:
                    {
                        metode = MetodeEnum.Romberg;
                        break;
                    }
                case 3:
                    {
                        metode = MetodeEnum.GaussLegrende;
                        break;
                    }
            }
        }

        private void metodeIntegralGanda_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (metodeIntegralGanda.SelectedIndex)
            {
                case 0:
                    {
                        metode = MetodeEnum.Trapesium;
                        break;
                    }
                case 1:
                    {
                        metode = MetodeEnum.Simpson1per3;
                        break;
                    }
                case 2:
                    {
                        metode = MetodeEnum.GaussLegrende;
                        break;
                    }
            }
        }

        private void metodeKimia_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (metodeKimia.SelectedIndex)
            {
                case 0:
                    {
                        metode = MetodeEnum.Trapesium;
                        break;
                    }
                case 1:
                    {
                        metode = MetodeEnum.Simpson1per3;
                        break;
                    }
                case 2:
                    {
                        metode = MetodeEnum.Romberg;
                        break;
                    }
                case 3:
                    {
                        metode = MetodeEnum.GaussLegrende;
                        break;
                    }
            }

            if (metodeKimia.SelectedIndex == 3) // Metode Gauss Legrende
            {
                OrdeGaussKimiaLabel.Visible = true;
                OrdeGaussKimiaNumericUpDown.Visible = true;
            }
            else
            {
                OrdeGaussKimiaLabel.Visible = false;
                OrdeGaussKimiaNumericUpDown.Visible = false;
                OrdeGaussKimiaNumericUpDown.Value = 3;
            }
        }

        private void metodeTransportasi_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (metodeTransportasi.SelectedIndex)
            {
                case 0:
                    {
                        metode = MetodeEnum.Trapesium;
                        break;
                    }
                case 1:
                    {
                        metode = MetodeEnum.Simpson1per3;
                        break;
                    }
                case 2:
                    {
                        metode = MetodeEnum.Simpson3per8;
                        break;
                    }
            }
        }

        private void metodeKelistrikan_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (metodeKelistrikan.SelectedIndex)
            {
                case 0:
                    {
                        metode = MetodeEnum.Trapesium;
                        break;
                    }
                case 1:
                    {
                        metode = MetodeEnum.Simpson1per3;
                        break;
                    }
                case 2:
                    {
                        metode = MetodeEnum.Romberg;
                        break;
                    }
                case 3:
                    {
                        metode = MetodeEnum.GaussLegrende;
                        break;
                    }
            }

            if (metodeKelistrikan.SelectedIndex == 3) // Metode Gauss Legrende
            {
                OrdeGaussKelistrikanLabel.Visible = true;
                OrdeGaussKelistrikanNumericUpDown.Visible = true;
            }
            else
            {
                OrdeGaussKelistrikanLabel.Visible = false;
                OrdeGaussKelistrikanNumericUpDown.Visible = false;
                OrdeGaussKelistrikanNumericUpDown.Value = 3;
            }
        }
        #endregion

        #region MenuItemClick
        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            openFileDialog1.Filter = "Text Files|*.txt";
            DialogResult dialogresult = openFileDialog1.ShowDialog();
            if (dialogresult.Equals(DialogResult.OK))
            {
                double[][] tempDebitSiangMalam = programUtil.openTable(openFileDialog1.FileName);
                tempDataDebitSiang = tempDebitSiangMalam[0].ToArray();
                tempDataDebitMalam = tempDebitSiangMalam[1].ToArray();
                
                dataGridDebit_TTransportasi.Rows.Clear();
                for (int i = 0; i < tempDataDebitSiang.Length; i++)
                {
                    dataGridDebit_TTransportasi.Rows.Add(tempDataDebitSiang[i].ToString(), tempDataDebitMalam[i].ToString());
                }

                tabControl1.SelectTab(tabBidangTransportasi.Name);
            }
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveFileDialog1.Filter = "PDF Files|*.pdf";
            DialogResult dialogresult = saveFileDialog1.ShowDialog();
            if (dialogresult.Equals(DialogResult.OK))
            {
                if (metode == MetodeEnum.Trapesium)
                {
                    trapesium.saveFile(saveFileDialog1.FileName);
                }
                else if (metode == MetodeEnum.TitikTengah)
                {
                    titiktengah.saveFile(saveFileDialog1.FileName);
                }
                else if (metode == MetodeEnum.Simpson1per3)
                {
                    simpson1per3.saveFile(saveFileDialog1.FileName);
                }
                else if (metode == MetodeEnum.Simpson3per8)
                {
                    simpson3per8.saveFile(saveFileDialog1.FileName);
                }
                else if (metode == MetodeEnum.GaussLegrende)
                {
                    gausslegendre.saveFile(saveFileDialog1.FileName);
                }
                else if (metode == MetodeEnum.Romberg)
                {
                    romberg.saveFile(saveFileDialog1.FileName);
                }
                else
                {
                    // ERROR INFO
                    MessageBox.Show("Pilihlah Metode yang benar untuk menyimpan pada " + saveFileDialog1.FileName);
                }
            }
        }
        #endregion

        #region DataGridViewAction
        private void dataGridDebit_TTransportasi_Validating(object sender, CancelEventArgs e)
        {
            List<double> tempDataDebitSiangList = new List<double>();
            List<double> tempDataDebitMalamList = new List<double>();

            foreach (DataGridViewRow row in dataGridDebit_TTransportasi.Rows)
            {
                try
                {
                    String siang = row.Cells[0].Value.ToString();
                    String malam = row.Cells[1].Value.ToString();
                    double siang_double = Double.Parse(siang);
                    double malam_double = Double.Parse(malam);
                    tempDataDebitSiangList.Add(siang_double);
                    tempDataDebitMalamList.Add(malam_double);
                    // DEBUG
                    // MessageBox.Show("Row Index: " + row.Index + " valid, with: "+siang_double+";"+malam_double);
                }
                catch (Exception exc)
                {
                    // DEBUG
                    // MessageBox.Show(exc.Message);
                    // MessageBox.Show("Row Index: " + row.Index + " is not valid");
                }
            }

            tempDataDebitSiang = tempDataDebitSiangList.ToArray();
            tempDataDebitMalam = tempDataDebitMalamList.ToArray();

            dataGridDebit_TTransportasi.Rows.Clear();

            for (int i = 0; i < tempDataDebitSiang.Length; i++)
            {
                // DEBUG
                // MessageBox.Show("Adding Row Index: " + i + " ; values: " + tempDataDebitSiang[i].ToString() + ";" + tempDataDebitMalam[i].ToString()); 
                dataGridDebit_TTransportasi.Rows.Add(tempDataDebitSiang[i].ToString(), tempDataDebitMalam[i].ToString());

            }
        }
        #endregion

        // Proses Hitung Integral
        private void HitungIntegral(double a, double b, double h, int n, int orde)
        {
            if (programUtil.CheckMetode(metode, n))
            {
                if (Double.IsInfinity(a) || Double.IsInfinity(b))
                {
                    // ERROR INFO
                    MessageBox.Show("Perhitungan Infinity masih belum dapat dilakukan");
                }
                else
                {
                    Console.WriteLine("================================================================");
                    Console.WriteLine("Mulai Hitung Integral");
                    Console.WriteLine(metode.ToString());
                    Console.WriteLine(soal.ToString());
                    Console.WriteLine(exp);
                    Console.WriteLine("a:" + a + " b:" + b);
                    Console.WriteLine("n:" + n);
                    Console.WriteLine("orde: " + orde);

                    // String Hasil Text
                    hasil1text = null;
                    hasil2text = null;
                    // Hasil Perhitungan
                    hasil = 0.0f;
                    hasil2 = 0.0f;
                    // x graph dan y graph
                    double[] x_graph = new double[] { 0, 1 };
                    double[] y_graph = new double[] { 0, 1 };
                    // String Column Header dan Column Name
                    columnHeader = new String[] {"1"};
                    columnName = new String[] {"Column1"};
                    // data-data pada datagrid
                    dataIterasi = new double[1][];
                    dataIterasi[0] = new double[] {0};

                    if (soal == SoalEnum.Matematika)
                    {
                        SubHitungWithExp(a, b, h, n, orde);
                        x_graph = new double[] { -5.0, 5.0 };
                        y_graph = new double[] { -1.0, 1.0 };
                    }
                    else if (soal == SoalEnum.Fisika1)
                    {
                        SubHitungWithExp(a, b, h, n, orde);
                        x_graph = new double[] { -5.0, 5.0 };
                        y_graph = new double[] { -1.0, 1.0 };
                    }
                    else if (soal == SoalEnum.Kimia)
                    {
                        // Mungkin diganti dengan SubHitungWithData
                        SubHitungWithExp(a, b, h, n, orde);
                        x_graph = new double[] { a - 5.0, b + 5.0 };
                        y_graph = new double[] { -10.0, 10.0 };
                    }
                    else if (soal == SoalEnum.Transportasi)
                    {
                        SubHitungSoalTransportasi(a, b, h, n, orde);
                        x_graph = new double[] { a - 5.0, b + 5.0 };
                        y_graph = new double[] { -10.0, 10.0 };
                    }
                    else if (soal == SoalEnum.Fisika2) // Tidak memakai expression
                    {
                        SubHitungWithExp(a, b, h, n, orde); 
                        // SubHitungSoalFisika2(a, b, h, n, orde);
                        x_graph = new double[] { a - 5.0, b + 5.0 };
                        y_graph = new double[] { -10.0, 10.0 };
                    }
                    else if (soal == SoalEnum.Kelistrikan)
                    {
                        SubHitungSoalKelistrikan(a, b, h, n, orde, a, b / 2);
                        x_graph = new double[] { 0.1, 1.0 };
                        y_graph = new double[] { -1.0, 170.0 };
                    }

                    // Result Form
                    if (resultForm == null || resultForm.IsDisposed)
                    {
                        resultForm = new ResultForm();
                    }

                    resultForm.SetupResultInfo(soal.ToString(), metode.ToString());
                    resultForm.SetupResultLabel(a, b, n);

                    // Data Grid
                    if (metode == MetodeEnum.Romberg)
                    {
                        resultForm.SetupDataGrid(columnHeader, columnName, dataIterasi, false);
                    }
                    else
                    {
                        resultForm.SetupDataGrid(columnHeader, columnName, dataIterasi, true);
                    }

                    // Graph
                    if (soal == SoalEnum.Kimia)
                    {
                        resultForm.RemovePerbandinganAnalitikKelistrikan();
                        resultForm.SetupGraph(x_graph, y_graph, new Expression[] { new Expression(exp) });
                        resultForm.ShowHasil("ln(f/P)", "f", hasil, hasil2);
                    }
                    else if (soal == SoalEnum.Transportasi)
                    {
                        resultForm.RemovePerbandinganAnalitikKelistrikan();
                        resultForm.RemoveGraph();
                        resultForm.ShowHasil("Siang", "Malam", hasil, hasil2);
                    }
                    else if (soal == SoalEnum.Fisika2)
                    {
                        resultForm.RemovePerbandinganAnalitikKelistrikan();
                        resultForm.SetupGraph(x_graph, y_graph, new Expression[] { new Expression(exp) });
                        resultForm.ShowHasil("T (g/L)^1/2", hasil2);
                    }
                    else if (soal == SoalEnum.Kelistrikan)
                    {
                        MathParser kelistrikanParser = new MathParser();
                        kelistrikanParser.Expression = programUtil.CreateIntegralKelistrikanExpression(1.0);
                        double analitikresult = 0.0;
                        kelistrikanParser.X = 0.5;
                        analitikresult = (double) kelistrikanParser.Value;
                        kelistrikanParser.X = 0.0;
                        analitikresult -= (double)kelistrikanParser.Value;
                        resultForm.SetupPerbandinganAnalitikKelistrikan(kelistrikanParser.Expression, analitikresult);
                        resultForm.SetupGraph(x_graph, y_graph, new Expression[] { new Expression(exp) });
                        resultForm.ShowHasil("I RMS", hasil);
                    }
                    else
                    {
                        resultForm.RemovePerbandinganAnalitikKelistrikan();
                        resultForm.SetupGraph(x_graph, y_graph, new Expression[] { new Expression(exp) });
                        resultForm.ShowHasil(hasil);
                    }

                    resultForm.Show();
                    // DEBUG
                    Console.WriteLine("Akhir Perhitungan Integral - ");
                }
            }
            else
            {
                // ERROR INFO
                MessageBox.Show("Perhitungan tidak bisa dilakukan\n\r" +
                    "Nilai n tidak sesuai dengan metode");
            }
        }

        // Proses Hitung Integral Ganda
        private void HitungIntegralGanda(double[] a, double[] b, double h, int[] n, int orde)
        {
            if (programUtil.CheckMetode(metode, n[0]) && programUtil.CheckMetode(metode, n[1]))
            {
                if (metode != MetodeEnum.Trapesium && 
                    metode != MetodeEnum.Simpson1per3 &&
                    metode != MetodeEnum.GaussLegrende)
                {
                    // ERROR INFO
                    MessageBox.Show("Metode " + metode.ToString() + " tidak disupport untuk integral ganda");
                }
                else
                {
                    Console.WriteLine("================================================================");
                    Console.WriteLine("Mulai Hitung Integral Ganda");
                    Console.WriteLine(metode.ToString());
                    Console.WriteLine(soal.ToString());
                    Console.WriteLine(exp);
                    Console.WriteLine("a0:" + a[0] + " a1:" + a[1] + " b0:"+ b[0] + "b1:"+ b[1]);
                    Console.WriteLine("n0:" + n[0] + " n1:" + n[1]);
                    Console.WriteLine("orde: " + orde);

                    // String Hasil Text
                    hasil1text = null;
                    // Hasil Perhitungan
                    hasil = 0.0f;
                    // String Column Header dan Column Name
                    columnHeader = new String[] { "X", "Y", "Integral Arah Y" };
                    columnName = new String[] { "ColumnX", "ColumnY", "ColumnIntegralArahY" };
                    // data-data pada datagrid
                    dataIterasi = new double[3][];

                    if (metode == MetodeEnum.Trapesium)
                    {
                        trapesium.setExpression(exp);
                        hasil = trapesium.integral_ganda(a[0], b[0], a[1], b[1], n[0], n[1]);
                        dataIterasi[0] = trapesium.dataX;
                        dataIterasi[1] = trapesium.dataY;
                        dataIterasi[2] = trapesium.tempRes;
                    }
                    else if (metode == MetodeEnum.Simpson1per3)
                    {
                        simpson1per3.setExpression(exp);
                        hasil = simpson1per3.integral_ganda(a[0], b[0], a[1], b[1], n[0], n[1]);
                        dataIterasi[0] = simpson1per3.dataX;
                        dataIterasi[1] = simpson1per3.dataY;
                        dataIterasi[2] = simpson1per3.tempRes;
                    }
                    else if (metode == MetodeEnum.GaussLegrende)
                    {
                        // Batasan Gauss Legrende
                        Console.WriteLine("Gauss Legendre Orde 2, n diubah menjadi 2");
                        
                        dataIterasi[0] = new double[] { 0.0, 0.5, 1.0 };
                        dataIterasi[1] = new double[] { 0.0, 0.5, 1.0 };
                        
                        double[] integral_arah_Y = new double[3];
                        String temp_exp = exp.Replace("x", "0.0");
                        temp_exp = temp_exp.Replace("y", "x");
                        integral_arah_Y[0] = gausslegendre.Integral(orde, temp_exp, a[0], b[0]);
                        temp_exp = exp.Replace("x", "0.5");
                        temp_exp = temp_exp.Replace("y", "x");
                        integral_arah_Y[1] = gausslegendre.Integral(orde, temp_exp, a[0], b[0]);
                        temp_exp = exp.Replace("x", "1.0");
                        temp_exp = temp_exp.Replace("y", "x");
                        integral_arah_Y[2] = gausslegendre.Integral(orde, temp_exp, a[0], b[0]);

                        hasil = simpson1per3.integral_data(dataIterasi[0], integral_arah_Y);
                        dataIterasi[2] = integral_arah_Y;
                    }

                    // Result Form
                    if (resultForm == null || resultForm.IsDisposed)
                    {
                        resultForm = new ResultForm();
                    }

                    resultForm.SetupResultInfo(soal.ToString(), metode.ToString());
                    resultForm.RemovePerbandinganAnalitikKelistrikan();
                    resultForm.SetupDataGrid(columnHeader, columnName, dataIterasi, true);
                    resultForm.SetupResultLabel(a[0], b[0], n[0]);
                    resultForm.RemoveGraph();
                    resultForm.ShowHasil(hasil);
                    resultForm.Show();

                    // DEBUG
                    Console.WriteLine("Akhir Perhitungan Integral Ganda -- ");
                }
            }
            else
            {
                // ERROR INFO
                MessageBox.Show("Perhitungan tidak bisa dilakukan\n\r" +
                    "Nilai n tidak sesuai dengan metode " + metode.ToString());
            }
        }

        // SubHitung1 untuk menghitung soal matematika, soal fisika1 dan soal kimia
        private void SubHitungWithExp(double a, double b, double h, int n, int orde)
        {
            if (metode == MetodeEnum.Trapesium)
            {
                hasil = trapesium.integral(exp, a, b, n);
                columnHeader = new String[] { "X", "Y" };
                columnName = new String[] { "ColumnX", "ColumnY" };
                dataIterasi = new double[2][]; 
                dataIterasi[0] = trapesium.dataX;
                dataIterasi[1] = trapesium.dataY;

                if (soal == SoalEnum.Kimia)
                {
                    Console.WriteLine("f(langsung dari integral): " + hasil);
                    hasil2 = Math.Exp(hasil) * b;
                    Console.WriteLine("f dari exp(integral)*P: " + hasil2);
                    trapesium.result = hasil2;
                }
                else if (soal == SoalEnum.Fisika2)
                {
                    Console.WriteLine("hasil: " + hasil);
                    hasil2 = hasil * 4; // Sudah dikali 4
                    trapesium.result = hasil2;
                    Console.WriteLine("hasil*4: " + hasil2);
                }
            }
            else if (metode == MetodeEnum.TitikTengah)
            {
                titiktengah.setExpression(exp);
                hasil = titiktengah.integral(a, b, n);
                columnHeader = new String[] { "X", "Y" };
                columnName = new String[] { "ColumnX", "ColumnY" }; 
                dataIterasi = new double[2][]; 
                dataIterasi[0] = titiktengah.dataX;
                dataIterasi[1] = titiktengah.dataY;

                if (soal == SoalEnum.Kimia)
                {
                    Console.WriteLine("f(langsung dari integral): " + hasil);
                    hasil2 = Math.Exp(hasil) * b;
                    Console.WriteLine("f dari exp(integral)*P: " + hasil2);
                    titiktengah.result = hasil2;
                }
                else if (soal == SoalEnum.Fisika2)
                {
                    Console.WriteLine("hasil: " + hasil);
                    hasil2 = hasil * 4; // Sudah dikali 4
                    titiktengah.result = hasil2;
                    Console.WriteLine("hasil*4: " + hasil2);
                }
            }
            else if (metode == MetodeEnum.Simpson1per3)
            {
                hasil = simpson1per3.integral(exp, a, b, n);
                columnHeader = new String[] { "X", "Y" };
                columnName = new String[] { "ColumnX", "ColumnY" }; 
                dataIterasi = new double[2][]; 
                dataIterasi[0] = simpson1per3.dataX;
                dataIterasi[1] = simpson1per3.dataY;
                
                if (soal == SoalEnum.Kimia)
                {
                    Console.WriteLine("f(langsung dari integral): " + hasil);
                    hasil2 = Math.Exp(hasil) * b;
                    Console.WriteLine("f dari exp(integral)*P: " + hasil2);
                    simpson1per3.result = hasil2;
                }
                else if (soal == SoalEnum.Fisika2)
                {
                    Console.WriteLine("hasil: " + hasil);
                    hasil2 = hasil * 4; // Sudah dikali 4
                    simpson1per3.result = hasil2;
                    Console.WriteLine("hasil*4: " + hasil2);
                }
            }
            else if (metode == MetodeEnum.Simpson3per8)
            {
                hasil = simpson3per8.integral(exp, a, b, n);
                columnHeader = new String[] { "X", "Y" };
                columnName = new String[] { "ColumnX", "ColumnY" }; 
                dataIterasi = new double[2][]; 
                dataIterasi[0] = simpson3per8.dataX;
                dataIterasi[1] = simpson3per8.dataY;

                if (soal == SoalEnum.Kimia)
                {
                    Console.WriteLine("f(langsung dari integral): " + hasil);
                    hasil2 = Math.Exp(hasil) * b;
                    Console.WriteLine("f dari exp(integral)*P: " + hasil2);
                    simpson3per8.result = hasil2;
                }
                else if (soal == SoalEnum.Fisika2)
                {
                    Console.WriteLine("hasil: " + hasil);
                    hasil2 = hasil * 4; // Sudah dikali 4
                    simpson3per8.result = hasil2;
                    Console.WriteLine("hasil*4: " + hasil2);
                }
            }
            else if (metode == MetodeEnum.GaussLegrende)
            {
                hasil = gausslegendre.Integral(orde, exp, a, b);
                columnHeader = new String[] { "X", "Y", "C * Y" };
                columnName = new String[] { "ColumnX", "ColumnY", "ColumnCxY" }; 
                dataIterasi = new double[3][]; 
                dataIterasi[0] = gausslegendre.dataX;
                dataIterasi[1] = gausslegendre.dataY;
                dataIterasi[2] = gausslegendre.suku;

                if (soal == SoalEnum.Kimia)
                {
                    Console.WriteLine("f(langsung dari integral): " + hasil);
                    hasil2 = Math.Exp(hasil) * b;
                    Console.WriteLine("f dari exp(integral)*P: " + hasil2);
                    gausslegendre.result = hasil2;
                }
                else if (soal == SoalEnum.Fisika2)
                {
                    Console.WriteLine("hasil: " + hasil);
                    hasil2 = hasil * 4; // Sudah dikali 4
                    gausslegendre.result = hasil2;
                    Console.WriteLine("hasil*4: " + hasil2);
                }
            }
            else if (metode == MetodeEnum.Romberg)
            {
                hasil = romberg.integral(a, b, n, exp);
                columnHeader = romberg.ColumnHeader;
                columnName = romberg.ColumnName;
                dataIterasi = new double[romberg.table.Length][];
                for (int i = 0; i < romberg.table.Length; i++)
                {
                    dataIterasi[i] = romberg.table[i];
                }

                if (soal == SoalEnum.Kimia)
                {
                    Console.WriteLine("f(langsung dari integral): " + hasil);
                    hasil2 = Math.Exp(hasil) * b;
                    Console.WriteLine("f dari exp(integral)*P: " + hasil2);
                    romberg.result = hasil2;
                }
                else if (soal == SoalEnum.Fisika2)
                {
                    Console.WriteLine("hasil: " + hasil);
                    hasil2 = hasil * 4; // Sudah dikali 4
                    romberg.result = hasil2;
                    Console.WriteLine("hasil*4: " + hasil2);
                }
            }
        }

        // SubHitung untuk menghitung soal transportasi
        private void SubHitungSoalTransportasi(double a, double b, double h, int n, int orde)
        {
            double[] tempDataDebitX = new double[tempDataDebitSiang.Length];
            // DEBUG
            // Console.WriteLine("Soal Transportasi:    X Length: "+tempDataDebitX.Length);
            for (int i = 0; i < tempDataDebitSiang.Length; i++)
            {
                tempDataDebitX[i] = i;
            }

            if (metode == MetodeEnum.Trapesium)
            {
                hasil = trapesium.integral_data(tempDataDebitX, tempDataDebitSiang);
                hasil2 = trapesium.integral_data(tempDataDebitX, tempDataDebitMalam);
            }
            else if (metode == MetodeEnum.Simpson1per3)
            {
                hasil = simpson1per3.integral_data(tempDataDebitX, tempDataDebitSiang);
                hasil2 = simpson1per3.integral_data(tempDataDebitX, tempDataDebitMalam);
            }
            else if (metode == MetodeEnum.Simpson3per8)
            {
                hasil = simpson3per8.integral_data(tempDataDebitX, tempDataDebitSiang);
                hasil2 = simpson3per8.integral_data(tempDataDebitX, tempDataDebitMalam);
            }

            columnHeader = new String[] { "X", "Y1", "Y2" };
            columnName = new String[] { "ColumnX", "ColumnY1", "ColumnY2" }; 
            dataIterasi = new double[3][];
            dataIterasi[0] = tempDataDebitX;
            dataIterasi[1] = tempDataDebitSiang;
            dataIterasi[2] = tempDataDebitMalam;
            // DEBUG
            // MessageBox.Show("Hasil Siang (1):" + hasil);
            // MessageBox.Show("Hasil Malam (2):" + hasil2);
        }

        // SubHitung untuk menghitung soal fisika 2
        // Tidak dipakai (tapi jangan dihapus)
        private void SubHitungSoalFisika2(double a, double b, double h, int n, int orde)
        {
            if (metode == MetodeEnum.Simpson3per8)
            {
                double[] dataX, dataY;
                programUtil.CreateDataFisika2(out dataX, out dataY);
                // Hasil di Metode juga harus dikali 4
                hasil = simpson3per8.integral_data(dataX, dataY);
                Console.WriteLine("hasil: " + hasil);
                hasil2 = hasil * 4; // Sudah dikali 4
                simpson3per8.result = hasil2;
                Console.WriteLine("hasil*4: " + hasil);
                columnHeader = new String[] { "X", "Y" };
                columnName = new String[] { "ColumnX", "ColumnY" };
                dataIterasi = new double[2][];
                dataIterasi[0] = simpson3per8.dataX;
                dataIterasi[1] = simpson3per8.dataY;
            }
            else
            {
                // ERROR INFO
                MessageBox.Show("Metode " + metode.ToString() + " kurang cocok untuk menyelesaikan Soal " + soal.ToString());
            }
        }

        // SubHitung untuk menghitung soal kelistrikan
        private void SubHitungSoalKelistrikan(double a, double b, double h, int n, int orde, double min_a, double max_b)
        {
            double[] tempDataX = programUtil.CreateDataX(a, b, n, min_a, max_b);
            double new_a = tempDataX[0];
            double new_b = tempDataX[tempDataX.Length - 1];
            int new_n = n / 2;
            Console.WriteLine("Pembuatan data X baru");
            Console.WriteLine("new a:" + new_a + " new_b:" + new_b);
            Console.WriteLine("n menjadi n baru yaitu: " + new_n);

            if (programUtil.CheckMetode(metode, new_n))
            {
                if (metode == MetodeEnum.Trapesium)
                {
                    hasil = trapesium.integral(exp, new_a, new_b, new_n);
                    columnHeader = new String[] { "X", "Y" };
                    columnName = new String[] { "ColumnX", "ColumnY" }; 
                    dataIterasi = new double[2][];
                    dataIterasi[0] = trapesium.dataX;
                    dataIterasi[1] = trapesium.dataY;
                }
                else if (metode == MetodeEnum.Simpson1per3)
                {
                    hasil = simpson1per3.integral(exp, new_a, new_b, new_n);
                    columnHeader = new String[] { "X", "Y" };
                    columnName = new String[] { "ColumnX", "ColumnY" }; 
                    dataIterasi = new double[2][];
                    dataIterasi[0] = simpson1per3.dataX;
                    dataIterasi[1] = simpson1per3.dataY;
                }
                else if (metode == MetodeEnum.Romberg)
                {
                    hasil = romberg.integral(new_a, new_b, new_n, exp);
                    columnHeader = romberg.ColumnHeader;
                    columnName = romberg.ColumnName;
                    dataIterasi = new double[romberg.table.Length][];
                    for (int i = 0; i < romberg.table.Length; i++)
                    {
                        dataIterasi[i] = romberg.table[i];
                    }
                }
                else if (metode == MetodeEnum.GaussLegrende)
                {
                    Console.WriteLine("Gauss Legendre memakai a dan b yang lama");
                    Console.WriteLine("a:" + a + " b:" + (b /2));
                    hasil = gausslegendre.Integral(orde, exp, a, b / 2);
                    columnHeader = new String[] { "X", "Y", "C * Y" };
                    columnName = new String[] { "ColumnX", "ColumnY", "ColumnCxY" };
                    dataIterasi = new double[3][];
                    dataIterasi[0] = gausslegendre.dataX;
                    dataIterasi[1] = gausslegendre.dataY;
                    dataIterasi[2] = gausslegendre.suku;
                }
            }
            else
            {
                // ERROR INFO
                MessageBox.Show("Perhitungan tidak bisa dilakukan\n\r" +
                    "Nilai n tidak sesuai dengan metode " + metode.ToString());
            }
        }

    }
}
